#include "Fire.h"
#include <random>
#include "SFML\Window\Keyboard.hpp"
#include "SFML\Window\Joystick.hpp"
#include "Objects/Particle.h"

#include <iostream>
using namespace std;

Fire::Fire(GameState *gameState) : PhysicalObject(gameState), m_player(0)
{
	addProperty("Fire");
	setLayer(2);

	getBodyDef()->type = b2_kinematicBody;
	getBodyDef()->fixedRotation = true;
	b2FixtureDef *fixDef = new b2FixtureDef;
	b2PolygonShape *shape = new b2PolygonShape;
	shape->SetAsBox(1.0f,1.0f);
	fixDef->isSensor = true;
	fixDef->shape = shape;
	fixDef->density = 2.0f;
	fixDef->restitution = 0.0f;
	addFixtureDef(fixDef);
	setRotation(0.0f);

	m_state = 0;
	m_time = 0;
	m_travelTime = 0;
	m_restoreTime = 0;
	m_maxRestoreTime = 0.25f;
	m_actionPressed = false;
	m_auraRadius = 0;
	m_maxAuraRadius = 15;
	m_auraTime = 0.0f;
	m_maxAuraTime = 0.3f;

	setColor(1.0f, 1.0f, 1.0f);
	setSize(b2Vec2(4.0f, 4.0f));

	m_shader = gameState->getShaderManager().getShader("fire");
	m_shader2 = gameState->getShaderManager().getShader("fireAura");
	
	SoundManager &soundManager = gameState->getSoundManager();
	m_fire1Sound.setBuffer(*soundManager.getSoundBuffer("fire1.wav"));
	
}


Fire::~Fire()
{
}


void Fire::update(double dt){
	bool actionPress = Keyboard::isKeyPressed(Keyboard::Space) || Joystick::isButtonPressed(0, 2) || Joystick::isButtonPressed(0, 5);
	bool action = actionPress;// && !m_actionPressed;

	if(actionPress){
		m_actionPressed = true;
	}else{
		m_actionPressed = false;
	}
	
	if(!m_alive){
		return;
	}
	b2Vec2 deltaPos = m_player->getPosition() - getPosition();

	static b2Vec2 lastPos;
	
	switch(m_state){
	case 0:
		//m_body->SetLinearVelocity(b2Vec2(deltaPos.x/dt, deltaPos.y/dt));
		m_vel = m_player->getBody()->GetLinearVelocity();
		setPosition(m_player->getPosition());
		m_travelTime = 0.0f;


		m_restoreTime += dt;
		if(m_restoreTime > m_maxRestoreTime){
			m_restoreTime = m_maxRestoreTime;
		}

		if(action && m_restoreTime >= m_maxRestoreTime/2.0f){
			m_state = 1;
			m_body->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
			m_restoreTime = 0;
			m_auraRadius = m_maxAuraRadius;

			for(int i = -2; i < 3; i++){
				for(int j = -1; j < 3; j++){
					b2Vec2 particlePos = b2Vec2(getPosition().x+i*0.1f, getPosition().y+j);
					b2Vec2 posSum = b2Vec2((((rand()%10)/10.0f)-0.5f)*0.5f, (((rand()%10)/10.0f)-0.5f)*0.5f);
					posSum *= 4.0f;
					particlePos += posSum;
				
					Particle *particle = m_gameState->getCurrentScreen()->createParticle();
					particle->setShader(m_gameState->getShaderManager().getShader("particle"));
					if(rand()%2){
						particle->setColor(1.0f, 0.4f, 0.15f, 0.3f);
					}else{
						particle->setColor(1.0f, 0.2f, 0.15f, 0.1f);
					}

					particle->setEndColor(0.2f, 0.2f, 0.2f, 0.0f);
					particle->setSize(b2Vec2(6.0f, 8.0f));
					particle->setPosition(particlePos);
					particle->setLifeTime(0.3f+rand()%6/20.0f);
					particle->setVel(b2Vec2((((rand()%10)/10.0f)-0.5f)*4, 8.0f));
					//, 1);
				}

				m_fire1Sound.play();
			}
		}
		break;
	case 1:
		m_auraTime+=dt;
		if(m_auraTime > m_maxAuraTime){
			m_auraTime = m_maxAuraTime;
		}

		if(deltaPos.LengthSquared() <= m_auraRadius*m_auraRadius){
			m_player->setInAura(true);
		}else{
			m_player->setInAura(false);
		}

		m_auraRadius-=2.5f*(float)dt;

		if(m_auraRadius<0.0f){
			m_auraRadius = 0.0f;
		}
		m_vel = b2Vec2(0.0f, 0.0f);
		if(!action){
			m_state = 2;
			m_auraTime = 0;
			m_player->setInAura(false);
		}
		break;
	case 2:
		b2Vec2 vel = deltaPos;
		float length = vel.Normalize();

		vel*=35.0f;
				
		for(int i = 0; i < 10; i++){
			b2Vec2 particlePos = lastPos;
			particlePos *= (1-(i/10.0f));
			b2Vec2 particlePos2 = getPosition();
			particlePos2 *= (i/10.0f);
			particlePos += particlePos2;
			particlePos.x += (((rand()%10)/10.0f)-0.5f)*0.5f;
			particlePos.y += (((rand()%10)/10.0f)-0.5f)*0.5f;
			b2Vec2 temp = vel;
			temp *= (float)dt;
			temp *= 0.5f;
			particlePos += temp;
			Particle *particle = m_gameState->getCurrentScreen()->createParticle();
			particle->setColor(1.0f, 0.4f, 0.15f);
			particle->setEndColor(0.2f, 0.2f, 0.2f);
			//particle->setColor(0.1f, 0.7f, 1.0f);
			particle->setSize(b2Vec2(3.0f, 3.0f));
			particle->setPosition(particlePos);
			//, 3);
		}

		m_body->SetLinearVelocity(vel);
		m_vel = b2Vec2(0.0f, 0.0f);
		m_travelTime += dt;
		//m_gameState->camera.shake(0.15.0f,0.55.0f);
		//m_fire1Sound.play();

		if(length <= 1.0f){
			m_state = 0;
			//m_gameState->camera.shake(0.15.0f,0.55.0f);
			setPosition(m_player->getPosition());
			m_body->SetLinearVelocity(m_vel);

			for(int i = -2; i < 3; i++){
				for(int j = -1; j < 3; j++){
					b2Vec2 particlePos = b2Vec2(getPosition().x+i*0.1f, getPosition().y+j*0.5f);
					b2Vec2 posSum = b2Vec2((((rand()%10)/10.0f)-0.5f)*0.5f, (((rand()%10)/10.0f)-0.5f)*0.5f);
					posSum *= 4.0f;
					particlePos += posSum;
				
					Particle *particle = m_gameState->getCurrentScreen()->createParticle();
					particle->setShader(m_gameState->getShaderManager().getShader("particle"));
					if(rand()%2){
						particle->setColor(1.0f, 0.4f, 0.15f, 0.3f);
					}else{
						particle->setColor(1.0f, 0.2f, 0.15f, 0.1f);
					}

					particle->setEndColor(0.2f, 0.2f, 0.2f, 0.0f);
					particle->setSize(b2Vec2(6.0f, 8.0f));
					particle->setPosition(particlePos);
					particle->setLifeTime(0.4f+rand()%6/20.0f);
					particle->setVel(b2Vec2((((rand()%10)/10.0f)-0.5f)*8, 6.0f));
					//, 1);
				}
			}
		}
	}

	float yDif = (getPosition().y - m_player->getPosition().y);
	
	m_gameState->camera.targetX = 0;
	m_gameState->camera.targetY = getPosition().y*0.3 + m_player->getPosition().y*0.7 + 8.0f;
	if(yDif > 30){
		if(getPosition().y > m_player->getPosition().y){
			m_gameState->camera.targetY -= yDif-30;
		}else{
			m_gameState->camera.targetY += yDif-30;
		}
	}

	static int direction = 1;
	lastPos = getPosition();
	m_time += dt*direction;

	if(m_time >= 3*3.1416f && direction == 1){
		direction = -1;
	}else if(m_time < 0.0f && direction == -1){
		direction = 1;
	}
}


void Fire::beginContact(b2Contact *contact){

}

void Fire::endContact(b2Contact *contact){

}

void Fire::PreSolve(b2Contact* contact, const b2Manifold* oldManifold){

}

void Fire::draw(){
	//drawFixtures();

	b2Vec2 pos = getPosition();
	if(m_state == 0){
		pos = m_player->getPosition();
	}
	 
	if(m_state == 1){
		sf::Shader::bind(m_shader2);

		m_shader2->setParameter("auraTime", (float)(m_auraTime/m_maxAuraTime));
	
		glPushMatrix();
		{
			glColor4f(1.0f, 1.0f, 0.9f, 0.17f);
			glTranslatef(pos.x, pos.y, 0); 
			glScalef(m_auraRadius*2, m_auraRadius*2, 1);
			glBegin(GL_QUADS);
			{
				glTexCoord2f(0.0f, 1.0f); glVertex3f( -0.5f, -0.5f, -0.2f);
				glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, -0.5f, -0.2f);
				glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, 0.5f, -0.2f);
				glTexCoord2f(0.0f, 0.0f); glVertex3f( -0.5f, 0.5f, -0.2f);
			}
			glEnd();
		}
		glPopMatrix();
		sf::Shader::bind(NULL);
	}

	b2Vec2 vel = m_vel;//m_body->GetLinearVelocity();
	float linVel = (16.0f-vel.Length())/16.0f;
	linVel *= 0.25f;
	linVel+=abs(vel.x)*0.25f;

	float velX = 0.0f; 
	float velY = 0.0f; 

	if(m_state==0){
		velX = (vel.x)/256.0f;
		velY = (vel.y)/256.0f;
	}

	// Color blending
	float blendTime = 0.15f;
	float sizeFactor = 1.6f;
	if(m_travelTime == 0){
		glColor3f(1.0f, 0.4f, 0.1f);
		if(m_state==0){
			sizeFactor *= float(m_restoreTime/m_maxRestoreTime);
		}
	}else if(m_travelTime <= blendTime){
		glColor3f(1.0f, 0.3f+0.7f*((float)m_travelTime*(1/blendTime)), 0.1f+0.6f*((float)m_travelTime*(1/blendTime)));
		sizeFactor -= 1.0f*((float)m_travelTime*(1/blendTime));
	}else{
		glColor3f(1.0f, 1.0f, 0.7f);
		sizeFactor = 0.6f;
	}

	sf::Shader::bind(m_shader);

	m_shader->setParameter("m_state", float(m_state));
	m_shader->setParameter("time", (float)m_time+2.0f);
	m_shader->setParameter("linVel", linVel);
	
	
	glPushMatrix();
	{
		glTranslatef(pos.x, pos.y, 0); 
		if(m_state==0 || m_state==1){
			glTranslatef(0, 0.5f, 0); 
		}
		glScalef(getSize().x*sizeFactor, getSize().y*sizeFactor, 1);
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0.0f, 1.0f); glVertex3f( -0.5f, -0.5f, -0.2f);
			glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, -0.5f, -0.2f);
			glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f-velX*2, 0.5f-velY*1.5f, -0.2f);
			glTexCoord2f(0.0f, 0.0f); glVertex3f( -0.5f-velX*2, 0.5f-velY*1.5f, -0.2f);
		}
		glEnd();
	}
	glPopMatrix();

	sf::Shader::bind(NULL);
	
}
